/**
 * Operating system operations.
 *
 * @author n1474335 [n1474335@gmail.com]
 * @copyright Crown Copyright 2016
 * @license Apache-2.0
 *
 * @namespace
 */
var OS = {

    /**
     * Parse UNIX file permissions operation.
     *
     * @param {string} input
     * @param {Object[]} args
     * @returns {string}
     */
    run_parse_unix_perms: function(input, args) {
        var perms = {
                d : false,  // directory
                sl : false, // symbolic link
                np : false, // named pipe
                s : false,  // socket
                cd : false, // character device
                bd : false, // block device
                dr : false, // door
                sb : false, // sticky bit
                su : false, // setuid
                sg : false, // setgid
                ru : false, // read user
                wu : false, // write user
                eu : false, // execute user
                rg : false, // read group
                wg : false, // write group
                eg : false, // execute group
                ro : false, // read other
                wo : false, // write other
                eo : false // execute other
            },
            d = 0,
            u = 0,
            g = 0,
            o = 0,
            output = "",
            octal = null,
            textual = null;
        
        if (input.search(/\s*[0-7]{1,4}\s*/i) === 0) {
            // Input is octal
            octal = input.match(/\s*([0-7]{1,4})\s*/i)[1];

            if (octal.length == 4) {
                d = parseInt(octal[0], 8);
                u = parseInt(octal[1], 8);
                g = parseInt(octal[2], 8);
                o = parseInt(octal[3], 8);
            } else {
                if (octal.length > 0) u = parseInt(octal[0], 8);
                if (octal.length > 1) g = parseInt(octal[1], 8);
                if (octal.length > 2) o = parseInt(octal[2], 8);
            }
            
            perms.su = d >> 2 & 0x1;
            perms.sg = d >> 1 & 0x1;
            perms.sb = d & 0x1;
                    
            perms.ru = u >> 2 & 0x1;
            perms.wu = u >> 1 & 0x1;
            perms.eu = u & 0x1;
            
            perms.rg = g >> 2 & 0x1;
            perms.wg = g >> 1 & 0x1;
            perms.eg = g & 0x1;
            
            perms.ro = o >> 2 & 0x1;
            perms.wo = o >> 1 & 0x1;
            perms.eo = o & 0x1;
        } else if (input.search(/\s*[dlpcbDrwxsStT-]{1,10}\s*/) === 0) {
            // Input is textual
            textual = input.match(/\s*([dlpcbDrwxsStT-]{1,10})\s*/)[1];
            
            switch (textual[0]) {
                case "d":
                    perms.d = true;
                    break;
                case "l":
                    perms.sl = true;
                    break;
                case "p":
                    perms.np = true;
                    break;
                case "s":
                    perms.s = true;
                    break;
                case "c":
                    perms.cd = true;
                    break;
                case "b":
                    perms.bd = true;
                    break;
                case "D":
                    perms.dr = true;
                    break;
            }
            
            if (textual.length > 1) perms.ru = textual[1] == "r";
            if (textual.length > 2) perms.wu = textual[2] == "w";
            if (textual.length > 3) {
                switch (textual[3]) {
                    case "x":
                        perms.eu = true;
                        break;
                    case "s":
                        perms.eu = true;
                        perms.su = true;
                        break;
                    case "S":
                        perms.su = true;
                        break;
                }
            }
            
            if (textual.length > 4) perms.rg = textual[4] == "r";
            if (textual.length > 5) perms.wg = textual[5] == "w";
            if (textual.length > 6) {
                switch (textual[6]) {
                    case "x":
                        perms.eg = true;
                        break;
                    case "s":
                        perms.eg = true;
                        perms.sg = true;
                        break;
                    case "S":
                        perms.sg = true;
                        break;
                }
            }
            
            if (textual.length > 7) perms.ro = textual[7] == "r";
            if (textual.length > 8) perms.wo = textual[8] == "w";
            if (textual.length > 9) {
                switch (textual[9]) {
                    case "x":
                        perms.eo = true;
                        break;
                    case "t":
                        perms.eo = true;
                        perms.sb = true;
                        break;
                    case "T":
                        perms.sb = true;
                        break;
                }
            }
        } else {
            return "Invalid input format.\nPlease enter the permissions in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format.";
        }
        
        output += "Textual representation: " + OS._perms_to_str(perms);
        output += "\nOctal representation:   " + OS._perms_to_octal(perms);
 
        // File type
        if (textual) {
            output += "\nFile type: " + OS._ft_from_perms(perms);
        }
        
        // setuid, setgid
        if (perms.su) {
            output += "\nThe setuid flag is set";
        }
        if (perms.sg) {
            output += "\nThe setgid flag is set";
        }
        
        // sticky bit
        if (perms.sb) {
            output += "\nThe sticky bit is set";
        }
        
        // Permission matrix
        output += "\n\n +---------+-------+-------+-------+\n" +
            " |         | User  | Group | Other |\n" + 
            " +---------+-------+-------+-------+\n" +
            " |    Read |   " + (perms.ru ? "X" : " ") + "   |   " + (perms.rg ? "X" : " ") + "   |   " + (perms.ro ? "X" : " ") + "   |\n" +
            " +---------+-------+-------+-------+\n" +
            " |   Write |   " + (perms.wu ? "X" : " ") + "   |   " + (perms.wg ? "X" : " ") + "   |   " + (perms.wo ? "X" : " ") + "   |\n" +
            " +---------+-------+-------+-------+\n" +
            " | Execute |   " + (perms.eu ? "X" : " ") + "   |   " + (perms.eg ? "X" : " ") + "   |   " + (perms.eo ? "X" : " ") + "   |\n" +
            " +---------+-------+-------+-------+\n";
 
        return output;
    },
    
    
    /**
     * Given a permissions object dictionary, generates a textual permissions string.
     *
     * @private
     * @param {Object} perms
     * @returns {string}
     */
    _perms_to_str: function(perms) {
        var str = "",
            type = "-";
            
        if (perms.d) type = "d";
        if (perms.sl) type = "l";
        if (perms.np) type = "p";
        if (perms.s) type = "s";
        if (perms.cd) type = "c";
        if (perms.bd) type = "b";
        if (perms.dr) type = "D";
        
        str = type;
        
        str += perms.ru ? "r" : "-";
        str += perms.wu ? "w" : "-";
        if (perms.eu && perms.su) {
            str += "s";
        } else if (perms.su) {
            str += "S";
        } else if (perms.eu) {
            str += "x";
        } else {
            str += "-";
        }
        
        str += perms.rg ? "r" : "-";
        str += perms.wg ? "w" : "-";
        if (perms.eg && perms.sg) {
            str += "s";
        } else if (perms.sg) {
            str += "S";
        } else if (perms.eg) {
            str += "x";
        } else {
            str += "-";
        }
        
        str += perms.ro ? "r" : "-";
        str += perms.wo ? "w" : "-";
        if (perms.eo && perms.sb) {
            str += "t";
        } else if (perms.sb) {
            str += "T";
        } else if (perms.eo) {
            str += "x";
        } else {
            str += "-";
        }
        
        return str;
    },
    
    
    /**
     * Given a permissions object dictionary, generates an octal permissions string.
     *
     * @private
     * @param {Object} perms
     * @returns {string}
     */
    _perms_to_octal: function(perms) {
        var d = 0,
            u = 0,
            g = 0,
            o = 0;
        
        if (perms.su) d += 4;
        if (perms.sg) d += 2;
        if (perms.sb) d += 1;
        
        if (perms.ru) u += 4;
        if (perms.wu) u += 2;
        if (perms.eu) u += 1;
        
        if (perms.rg) g += 4;
        if (perms.wg) g += 2;
        if (perms.eg) g += 1;
        
        if (perms.ro) o += 4;
        if (perms.wo) o += 2;
        if (perms.eo) o += 1;
        
        return d.toString() + u.toString() + g.toString() + o.toString();
    },
    
    
    /**
     * Given a permissions object dictionary, returns the file type.
     *
     * @private
     * @param {Object} perms
     * @returns {string}
     */
    _ft_from_perms: function(perms) {
        if (perms.d) return "Directory";
        if (perms.sl) return "Symbolic link";
        if (perms.np) return "Named pipe";
        if (perms.s) return "Socket";
        if (perms.cd) return "Character device";
        if (perms.bd) return "Block device";
        if (perms.dr) return "Door";
        return "Regular file";
    },
    
};
